// We're testing x86 target specific features
//@only-target: x86_64 i686

//! rsqrt and rcp SSE/AVX operations are approximate. We use that as license to treat them as
//! non-deterministic. Ensure that we do indeed see random results within the expected error bounds.

#[cfg(target_arch = "x86")]
use std::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;
use std::collections::HashSet;

fn main() {
    let a = unsafe { _mm_setr_ps(4.0, 4.0, 4.0, 4.0) };
    let exact = 0.5;
    // max error: 2^-12.
    let rel_error_bound = 1.0 / (1 << 12) as f32;

    let mut vals = HashSet::new();
    for _ in 0..50 {
        // Compute the inverse square root of 4.0, four times.
        let r = unsafe { _mm_rsqrt_ps(a) };
        let r: [f32; 4] = unsafe { std::mem::transmute(r) };
        // Check the results.
        for r in r {
            vals.insert(r.to_bits());
            // Ensure the relative error is no more than 2^-12.
            let rel_error = (r - exact) / exact;
            assert!(
                rel_error.abs() <= rel_error_bound,
                "correct result: {exact}, got: {r}\n\
                that's a relative error of {rel_error} (= 2^{log_error})",
                log_error = rel_error.abs().log2()
            );
        }
    }
    // Ensure we saw a bunch of different results.
    assert!(vals.len() >= 50);
}
